Skip to main content

Two-Crystal Ball Problem

Given two crystal balls that will break if dropped from a high-enough distance, determine the exact spot at which it will break in the most optimized way.

Sometimes you receive the problem in the context of a building and you need to find the highest floor at which the ball will break.

Generalization​

The floors can be thought of as an array of booleans, where true means the ball will break and false means the ball will not break.

floors [ false false ... true true ... ]
| | |
0 | n
|
i

If we use linear search and start at 0, we will eventually find the first true value. But this doesn't utilize our constraints: we have two balls. The time complexity is .

We know that this array is ordered, so we can use binary search to find the first true value.

floors [ false false ... floors[i] = true? ... ]
| | |
0 | n
|
i = 0.5n

Well, if it's true, one of the balls broke. We will have to linearly search from 0 to i using the other ball to find the exact spot. If we run linear searches, the time complexity is .

Both of these approaches suck.

The problem is that we are jumping a portion of . We need to use a fundamentally different unit. For example, we can jump by .

floors [ f f ... t t t t t t t t t t t t ... t ]
| | | | |
0<--------|-------->|-------->|-------->n
sqrt(n)

In the worst case, we are running forward at most times, going back, and then linearly searching the last floors.

So, the time complexity is which is .

Implementation​

fn two_crystal_balls(breaks: &[bool]) -> u8 {
let jump_size = (breaks.len() as f64).sqrt() as usize;
let mut i = jump_size;
while i < breaks.len() {
if breaks[i] {
break;
}
i += jump_size;
}
// linear search from i - jump_size to i
for j in (i - jump_size)..i {
if breaks[j] {
return j as u8;
}
}
unreachable!()
}